package generator

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/token"
	"strings"

	"github.com/yourusername/gox/pkg/parser"
)

// Generator 代码生成器
type Generator struct {
	fset *token.FileSet
}

// NewGenerator 创建新的代码生成器
func NewGenerator(fset *token.FileSet) *Generator {
	return &Generator{
		fset: fset,
	}
}

// Generate 生成标准的 Go 代码
func (g *Generator) Generate(goxFile *parser.GoxFile) ([]byte, error) {
	// 生成代码的缓冲区
	var buf bytes.Buffer

	// 生成包声明
	if goxFile.Name != nil {
		fmt.Fprintf(&buf, "package %s\n\n", goxFile.Name.Name)
	}

	// 生成导入语句，确保包含运行时库
	g.generateImports(&buf, goxFile)

	// 生成函数和类型定义
	for _, decl := range goxFile.Decls {
		// 跳过导入声明，因为我们已经重新生成了
		if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.IMPORT {
			continue
		}

		formatted, err := g.formatDeclaration(decl)
		if err != nil {
			return nil, fmt.Errorf("格式化声明失败: %w", err)
		}
		buf.WriteString(formatted)
		buf.WriteString("\n\n")
	}

	// 格式化最终代码
	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		return nil, fmt.Errorf("格式化代码失败: %w", err)
	}

	return formatted, nil
}

// generateImports 生成导入语句
func (g *Generator) generateImports(buf *bytes.Buffer, goxFile *parser.GoxFile) {
	imports := make(map[string]string)
	hasRuntimeImport := false

	// 提取现有的导入
	for _, decl := range goxFile.Decls {
		if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.IMPORT {
			for _, spec := range genDecl.Specs {
				if importSpec, ok := spec.(*ast.ImportSpec); ok {
					path := strings.Trim(importSpec.Path.Value, `"`)
					name := ""
					if importSpec.Name != nil {
						name = importSpec.Name.Name
					}
					imports[path] = name

					if path == "github.com/yourusername/gox/pkg/runtime" {
						hasRuntimeImport = true
					}
				}
			}
			// 跳过这个导入声明，稍后重新生成
			continue
		}
	}

	// 如果有 SQL 块，确保导入运行时库和 fmt 包
	if len(goxFile.SQLBlocks) > 0 {
		if !hasRuntimeImport {
			imports["github.com/yourusername/gox/pkg/runtime"] = ""
		}
		// 检查是否需要 fmt 包（对于表达式插入）
		needsFmt := false
		for _, block := range goxFile.SQLBlocks {
			for _, node := range block.Content {
				if _, ok := node.(*parser.SQLExpression); ok {
					needsFmt = true
					break
				}
			}
			if needsFmt {
				break
			}
		}
		if needsFmt {
			imports["fmt"] = ""
		}
	}

	// 生成导入语句
	if len(imports) > 0 {
		buf.WriteString("import (\n")
		for path, name := range imports {
			if name != "" {
				fmt.Fprintf(buf, "\t%s \"%s\"\n", name, path)
			} else {
				fmt.Fprintf(buf, "\t\"%s\"\n", path)
			}
		}
		buf.WriteString(")\n\n")
	}
}

// formatDeclaration 格式化声明
func (g *Generator) formatDeclaration(decl ast.Decl) (string, error) {
	var buf bytes.Buffer
	err := format.Node(&buf, g.fset, decl)
	if err != nil {
		return "", err
	}
	return buf.String(), nil
}

// GenerateExample 生成示例代码
func (g *Generator) GenerateExample() string {
	return `package main

import (
	"database/sql"
	"fmt"
	"log"
	
	"github.com/yourusername/gox/pkg/runtime"
	_ "github.com/lib/pq" // PostgreSQL driver
)

type User struct {
	ID        int
	Name      string
	Email     string
	CreatedAt string
}

func GetUser(db *sql.DB, userID int, status string) (*User, error) {
	// 这是编译后的代码，原始的 .gox 文件中是:
	// query := <sql>
	//     SELECT id, name, email, created_at 
	//     FROM users 
	//     WHERE id = {userID} 
	//     AND status = {status}
	//     ORDER BY created_at DESC
	// </sql>
	
	__gox_sql_0_builder := runtime.NewQueryBuilder()
	__gox_sql_0_builder.AddText("SELECT id, name, email, created_at FROM users WHERE id = ")
	__gox_sql_0_builder.AddParam(userID)
	__gox_sql_0_builder.AddText(" AND status = ")
	__gox_sql_0_builder.AddParam(status)
	__gox_sql_0_builder.AddText(" ORDER BY created_at DESC")
	query := __gox_sql_0_builder.Build()
	
	row := db.QueryRow(query.String(), query.Args()...)
	
	var user User
	err := row.Scan(&user.ID, &user.Name, &user.Email, &user.CreatedAt)
	if err != nil {
		return nil, err
	}
	
	return &user, nil
}

func main() {
	// 数据库连接示例
	db, err := sql.Open("postgres", "user=username dbname=mydb sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	
	user, err := GetUser(db, 1, "active")
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("User: %+v\n", user)
}`
}
